/*********************************************************************
* File: Communication.cpp
*
* \brief Implements the communication API.
*
* \author Instituto Superior Tecnico de Lisboa, Portugal
* \author Technical University of Lisbon, Portugal
* 
* \author Agentes Autonomos e Sistemas Multiagente
* \author Autonomous Agents and Multiagent Systems
* 
* \version	1.0
* \date		2006/2007
*********************************************************************/
#include "Communication.h"
#include "../../util/util.h"
#include "../Agent.h"
using namespace agents;
#pragma warning( disable : 4482 )  // Disable warning messages

/**
* \brief The class constructor.
*
* \param[in] The agent.
**/
Communication::Communication(Agent &owner)
:_owner(owner)
{
	_sayMsgInbox = new queue<MessageRecord*>;
	_sayTeamMsgInbox = new queue<MessageRecord*>;
	_sayDeadMsgInbox = new queue<MessageRecord*>;
	_radioMsgInbox = new queue<RadioMessageRecord*>;
}

/**
* \brief The class destructor.
**/
Communication::~Communication()
{
	if(_sayMsgInbox != 0)
		delete _sayMsgInbox;
	if(_sayTeamMsgInbox != 0)
		delete _sayTeamMsgInbox;
	if(_sayDeadMsgInbox != 0)
		delete _sayDeadMsgInbox;
	if(_radioMsgInbox != 0)
		delete _radioMsgInbox;
}

/**
* \brief Setups for the new round. 
* 
* Should be invoked when a new round starts.
**/
void Communication::newRound(){
}

//BUG 03: Agents can't chat with each other: Start
/**
* \brief Appends the id prefix to the message.
**/
void appendPrefixToMessage(char dest[MAX_MESSAGE_SIZE + 10], const char* msg, edict_t* sender)
{
	char prefix[10];
	sprintf(prefix, "%d:", ENTINDEX(sender));
	strcpy(dest, prefix);
	strcat(dest, msg);
}
/**
* \brief Say something. 
*
* Corresponds to simulating a chat message.
*
* \param[in] msg The message.
*
* \see agents::interfaces::ICommunication::sayText
**/
void Communication::sayText(const char *msg)
{
	if (util::isNullString(msg))
		return;

	char buffer[MAX_MESSAGE_SIZE + 10];
	appendPrefixToMessage(buffer, msg, _owner.getEdict());
	util::fakeClientCommand(_owner.getEdict(), "say \"%s\"", buffer);
}
/**
* \brief Say something to the team. 
*
* Corresponds to simulating a team chat message.
*
* \param[in] msg The message.
*
* \see agents::interfaces::ICommunication::sayText
**/
void Communication::teamSayText(const char *msg)
{
	if (util::isNullString(msg))
		return;

	char buffer[MAX_MESSAGE_SIZE + 10];
	appendPrefixToMessage(buffer, msg, _owner.getEdict());
	util::fakeClientCommand(_owner.getEdict(), "say_team \"%s\"", buffer);
}
//BUG 03: End

/**
* \brief Gets the next received chat message of a certain type.
*
* \param[in] sayMsgType The type of msg we want to check if have been sent.
* \param[out] record Is filled with message information.
* \return If no message of that type was received, 'false'; otherwise, 'true'.
*
* \see agents::interfaces::ICommunication::receiveMsg
**/
bool Communication::receiveMsg(SayMessages::Enumeration sayMsgType, MessageRecord* record)
{
	switch(sayMsgType)
	{
	case SayMessages::sayMsg:
		return receiveMsg(_sayMsgInbox, record);
	case SayMessages::sayTeamMsg:
		return receiveMsg(_sayTeamMsgInbox, record);
	case SayMessages::sayDeadMsg:
		return receiveMsg(_sayDeadMsgInbox, record);
	default:
		return false;
	}
}

/**
* \brief Gets the next received chat message of a certain type.
*
* \param[in] inbox The appropriate message inbox.
* \param[out] record Is filled with message information.
* \return If no message was received, 'false'; otherwise, 'true'.
**/
bool Communication::receiveMsg(queue<MessageRecord*>* inbox, MessageRecord* record)
{
	MessageRecord *temp;

	if(inbox->size() == 0)
		return false;

	temp = inbox->front();
	inbox->pop();

	char* msg = (char*) malloc((strlen(temp->msg)+1)*sizeof(char*));
	strcpy(msg, temp->msg);
	record->msg = msg;
	record->sender = temp->sender;
	record->timeStamp = temp->timeStamp;
	delete temp;

	return true;
}

/**
* \brief Send a radio message.
*
* \param[in] msg The message.
*
* \see agents::interfaces::ICommunication::sendRadioMessage
**/
void Communication::sendRadioMessage(RadioMessages::Enumeration msg)
{
	if (!g_radioCommunicationActive)
		return;

	int radioSelect = msg;

	int team = util::getTeam(_owner.getEdict());

	Agent** agents = g_world->agents;
	Agent* agent;
	for (int i = 0; i < gpGlobals->maxClients; i++)
	{
		if (agents[i])
			if (_owner.pev != agents[i]->pev && util::getTeam(agents[i]->getEdict()) == team)
			{
				agent = (Agent*) agents[i];
				agent->communication->pushRadioMessage((RadioMessages::Enumeration) radioSelect, _owner.getEdict());
			}
	}

	if (radioSelect < ICommunication::RadioMessages::goGoGo)
		util::fakeClientCommand(_owner.getEdict(), "radio1");
	else if (radioSelect < ICommunication::RadioMessages::affirmative)
	{
		radioSelect -= ICommunication::RadioMessages::goGoGo - 1;
		util::fakeClientCommand(_owner.getEdict(), "radio2");
	}
	else
	{
		radioSelect -= ICommunication::RadioMessages::affirmative - 1;
		util::fakeClientCommand(_owner.getEdict(), "radio3");
	}

	// Simulate pressing the right item from the radio commands menu
	util::fakeClientCommand(_owner.getEdict(), "menuselect %d", radioSelect);
}
/**
* \brief Gets the next received radio message of a certain type.
*
* \param[out] record Is filled with message information.
* \return If no message was received, 'false'; otherwise, 'true'.
*
* \see agents::interfaces::ICommunication::receiveRadioMsg
**/
bool Communication::receiveRadioMsg(RadioMessageRecord* record)
{
	RadioMessageRecord *temp;

	if(_radioMsgInbox->size() == 0)
		return false;

	temp = _radioMsgInbox->front();
	_radioMsgInbox->pop();

	record->msg = temp->msg;
	record->sender = temp->sender;
	record->timeStamp = temp->timeStamp;
	delete temp;

	return true;
}

/**
* \brief Creates a say message record.
*
* \param[in] msg The message.
* \param[in] sender The sender's entity.
**/
ICommunication::MessageRecord* Communication::createMessageRecord(const char* msg, edict_t *sender)
{
	ICommunication::MessageRecord *record = new ICommunication::MessageRecord();
	char* storeMsg = (char*) malloc((strlen(msg)+1)*sizeof(char*));
	strcpy(storeMsg,msg);
	record->msg = storeMsg;
	if(sender != NULL)
	{
		strcpy(record->sender.name, STRING(sender->v.netname));
		record->sender.radarUnit.set(_owner.getNavigation().getPosition(),
			sender->v.origin, _owner.getTeam() == util::getTeam(sender), false, false);
	}
	record->timeStamp = gpGlobals->time;

	return record;
}
/**
* \brief Handles received chat messages.
*
* \param[in] msg The message.
* \param[in] sender The sender's entity.
**/
void Communication::pushSayMessage(const char* msg, edict_t *sender)
{
	_sayMsgInbox->push(createMessageRecord(msg, sender));
}

/**
* \brief Handles received team chat messages.
*
* \param[in] msg The message.
* \param[in] sender The sender's entity.
**/
void Communication::pushSayTeamMessage(const char* msg, edict_t *sender)
{
	_sayTeamMsgInbox->push(createMessageRecord(msg, sender));
}

/**
* \brief Handles say messages from dead. 
*
* Only is called if both sender and receiver are dead.
*
* \param[in] msg The message.
* \param[in] sender The sender's entity.
**/
void Communication::pushSayDeadMessage(const char* msg, edict_t *sender)
{
	_sayDeadMsgInbox->push(createMessageRecord(msg, sender));
}

/**
* \brief Handles received radio messages.
*
* \param[in] msg The radio message.
* \param[in] sender The sender's entity.
**/
void Communication::pushRadioMessage(RadioMessages::Enumeration msg, edict_t* sender)
{
	RadioMessageRecord *record = new RadioMessageRecord();
	record->msg = msg;
	strcpy(record->sender.name, STRING(sender->v.netname));
	record->sender.radarUnit.set(_owner.getNavigation().getPosition(),
		sender->v.origin, true, false, false);
	record->timeStamp = gpGlobals->time;

	_radioMsgInbox->push(record);
}